/*
 * Copyright (C) 2019-2020 Alibaba Group Holding Limited
 */

#include <vfs.h>
#include "app_main.h"
#include <http_client.h>
#include <time.h>
#define TEST_TIMES 1
#define TEST_BUFFER_SIZE (1*1024)
#define TEST_DATA_MBYTE (TEST_TIMES*TEST_BUFFER_SIZE/1024/1024)
static void print_help(void)
{
    printf("Supported commands:\n"
           "led\n"
           "lef_rgb\n"
           "led_array\n"
           "lpm\n"
           "power_off\n"
           "wifiips\n"
           "voldbg\n"
           "mac\n"
           "mic\n"
           "pa\n"
           "ldo\n"
           "battery\n"
           "clock\n"
           "wifi_prov\n"
           "lfs\n");
}

void http_download(const char *url, const char *save_dir)
{
    int http_response_size = 4 * 1024;
    char *buffer = aos_malloc_check(http_response_size + 1);
    int rec_fd = 0;
    char save_path[128];
    int content_length = 0, total_read_len = 0, read_len = 0;

    if (!save_dir || strlen(save_dir) < 2) {
        printf("save path err\n");
        return;
    }

    if (!wifi_internet_is_connected()) {
        printf("network not connected!\n");
        return;
    }

    if (save_dir[strlen(save_dir) - 1] == '/') {
        snprintf(save_path, 128, "%s%s", save_dir, strrchr(url, '/') + 1);
    } else {
        snprintf(save_path, 128, "%s/%s", save_dir, strrchr(url, '/') + 1);
    }

    rec_fd = aos_open(save_path, O_WRONLY | O_CREAT | O_TRUNC);
    if (rec_fd < 0) {
        printf("Create file %s error\n", save_path);
        return;
    }

    http_client_config_t config = {
        .url = url,
        //.event_handler = _http_event_handler,
        .timeout_ms = 10000,
        .buffer_size = 4 * 1024,
        // .cert_pem = ca_cert,
    };

    http_client_handle_t client = http_client_init(&config);
    if (client == NULL) {
        printf("http request init failed, url \"%s\"\n", url);
        return;
    }

    http_errors_t err;
    if ((err = http_client_open(client, 0)) != HTTP_CLI_OK) {
        printf("Failed to open HTTP connection: 0x%x\n", err);
        goto http_err;
    }

    content_length =  http_client_fetch_headers(client);
    while (total_read_len < content_length) {
        read_len = http_client_read(client, buffer, http_response_size);
        if (read_len <= 0) {
            printf("Error read data\n");
            goto http_err;
        }

        int wsize = aos_write(rec_fd, buffer, read_len);
        if (wsize != read_len) {
            printf("write sd failed %d %d\n", wsize, read_len);
            goto http_err;            
        }

        total_read_len += read_len;
    }
    printf("download finished, save to %s!\n", save_path);

http_err:    
    http_client_cleanup(client);
    aos_free(buffer);
    aos_close(rec_fd);
}

static void clock_print_help(void)
{
    printf("app clock usage:\n"
           "app clock del <clock_id>: delete clock <id>\n"
           "app clock set <clock_id> <period> <hour> <minute> <second>: create a new alarm\n"
           "app clock get: get all set alarms\n");
}

static void lfs_test_read(void)
{
    int fd = aos_open("/lfs/lfs_test.txt", O_RDONLY);
    if (fd < 0) {
        printf("file not create, pls create first\n");
    }

    int   buff_size = TEST_BUFFER_SIZE;
    char *buff      = malloc(buff_size);
    memset(buff, 0xAA, buff_size);

    printf("START\n");
    int beg = aos_now_ms();
    for (int i = 0; i < TEST_TIMES; i++) {
        if (aos_read(fd, buff, buff_size) < 0) {
            printf("read error\n");
        }
    }
    int end = aos_now_ms();
    printf("END");
    printf("%.3fMB/s",  (float)(TEST_DATA_MBYTE * 1000.0) / (float)(end - beg) );

    free(buff);
    aos_close(fd);
}

static void lfs_test_write(void)
{
    int i = 0;
    int total = 0;
    int   buff_size = TEST_BUFFER_SIZE;
    char *buff      = malloc(buff_size);
    memset(buff, 0x55, buff_size);

    for (i = 0; i < TEST_TIMES; i++) {
        int fd = aos_open("/lfs/lfs_test.txt", O_CREAT | O_RDWR);
        if (fd < 0) {
            printf("aos_open fail");
        }

        printf("START");
        int beg = aos_now_ms();
            if (aos_write(fd, buff, buff_size) < 0) {
                printf("write error\n");
            }
        int end = aos_now_ms();
        printf("END");
        total += (end - beg);
        aos_close(fd);
    }
    printf("%.3fMB/s",  (float)(TEST_DATA_MBYTE * 1000.0) / (float)total);
    free(buff);
}

static void lcd_init(uint32_t baud)
{
#if defined(CONFIG_LCD_ILI9488) && CONFIG_LCD_ILI9488
    /* LCD屏幕初始化 */
    ili9488_gpio_pin_t lcd_pin = {
        .spi_cs = SPI_CS,
        .spi_rs = SPI_RS,
        .spi_reset = SPI_RESET,
        .usi_spi_idx = USI_SPI_IDX
    };
    LCD_Init(&lcd_pin, baud);
    printf("set lcd spi baud %d\n", baud);
#endif
}

static void cmd_app_func(char *wbuf, int wbuf_len, int argc, char **argv)
{
    int ret = 0;

    if (argc < 2) {
        print_help();
        return;
    }

    if (strcmp(argv[1], "led") == 0) {

        if (strcmp(argv[2], "off") == 0) {
            app_set_led_enabled(0);
            app_set_led_state(LED_TURN_OFF);
        } else {
            app_set_led_enabled(1);

            int stat = atoi(argv[2]);
            app_set_led_state(stat);
        }
    } else if (strcmp(argv[1], "lcdinit") == 0) {
        lcd_init(atoi(argv[2]) * 1000000);
    } else if (strcmp(argv[1], "lpm") == 0) {
        if (app_lpm_check()) {
            if (argc == 3) {
                int mode = atoi(argv[2]);
                if (mode == 1) {
                    pm_config_policy(LPM_POLICY_LOW_POWER);
                } else if (mode == 2) {
                    pm_config_policy(LPM_POLICY_DEEP_SLEEP);
                }
            }
            pm_agree_halt(0);
        } else {
            printf("\tlpm check failed\n");
        }
    } else if (strcmp(argv[1], "power_off") == 0) {
        // app_lpm_sleep(LPM_POLICY_DEEP_SLEEP, 1);
    } else if (strcmp(argv[1], "wifips") == 0) {
        wifi_set_lpm(atoi(argv[2]));
    } else if (strcmp(argv[1], "mac") == 0) {
        uint8_t mac[6];
        wifi_getmac(mac);
        printf("%02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    } else if (strcmp(argv[1], "rtc") == 0) {
        if (argc <= 6) {
            int arg2 = atoi(argv[2]);
            switch(arg2)
            {
            case 1:
                rtc_from_system();
                break;
            case 2:
                rtc_to_system();
                break;
            case 3: {
                extern void rtc_debug(void);
                rtc_debug();
                }
                break;
            case 4: {
                struct tm tm_set;
                tm_set.tm_wday = atoi(argv[3]);
                tm_set.tm_mday  = atoi(argv[4]);
                tm_set.tm_hour = atoi(argv[5]);
                tm_set.tm_min  = atoi(argv[6]);
                tm_set.tm_sec = 0;
                rtc_set_alarm(&tm_set);
                }
                break;
            default:
                ;
            }
        }
    } else if (strcmp(argv[1], "clock") == 0) {
        if (argc < 3) {
            clock_print_help();
        }
        int id = 0;
        if (strcmp(argv[2], "del") == 0) {
            id  = atoi(argv[3]);
            ret = clock_alarm_set(id, NULL);
            printf("clock alarm: clock id %d is delete. ret %d\n", id, ret);
        } else if (strcmp(argv[2], "set") == 0) {
            id = atoi(argv[3]);
            clock_alarm_config_t cli_time;
            cli_time.period = atoi(argv[4]);
            cli_time.hour   = atoi(argv[5]);
            cli_time.min    = atoi(argv[6]);
            cli_time.sec    = atoi(argv[7]);

            printf("set alarm: id %d, period %d, time %02d:%02d:%02d\n", id, cli_time.period,
                   cli_time.hour, cli_time.min, cli_time.sec);
            id = clock_alarm_set(id, &cli_time);
            if (id == -2) {
                printf("clock alarm has repeat time.\n");
                return;
            } else if (id == -1) {
                printf("clock alarm has full.\n");
                return;
            } if (id == -4) {
                printf("clock alarm time config error.\n");
                return;
            } else {
                clock_alarm_enable(id, 1);
                printf("clock id %d set success. time %02d:%02d:%02d, period %d.\n", id,
                       cli_time.hour, cli_time.min, cli_time.sec, cli_time.period);
            }
        } else if (strcmp(argv[2], "get") == 0) {
            clock_alarm_ctx_t *clock_info;
            struct tm *        clock_tm;
            uint8_t has_clock = 0;
            for (uint8_t idx = 1; idx < CLOCK_ALARM_NUM+1; idx++) {
                clock_info = NULL;
                clock_info = clock_alarm_get(idx);
                if (NULL != clock_info) {
                    clock_tm = gmtime(&clock_info->time);
                    printf("clock id[%d], time[%02d:%02d:%02d], period[%d], enable[%d]\n", clock_info->id,
                           clock_tm->tm_hour, clock_tm->tm_min, clock_tm->tm_sec,
                           clock_info->period, clock_info->enable);
                    has_clock = 1;
                }
            }
            if(0 == has_clock) {
                printf("no clock alarm set!\n");
            }
        }
    } else if (strcmp(argv[1], "wifi_prov") == 0) {
        extern int wifi_prov_method;
        if (strcmp(argv[2], "softap") == 0) {
            wifi_prov_method = WIFI_PROVISION_SOFTAP;
            printf("wifi provision method switch to softap!\n");
        } else if (strcmp(argv[2], "dev_ap") == 0) {
            wifi_prov_method = WIFI_PROVISION_SL_DEV_AP;
            printf("wifi provision method switch to smartliving device ap!\n");
        } else if (strcmp(argv[2], "smartconfig") == 0) {
            wifi_prov_method = WIFI_PROVISION_SL_SMARTCONFIG;
            printf("wifi provision method switch to smartliving smartconfig!\n");
        } else {
            printf("app wifi_prov softap/dev_ap/smartconfig");
        }
    } else if (strcmp(argv[1], "lfs") == 0) {
        if (strcmp(argv[2], "read") == 0) {
            lfs_test_read();
        } else if (strcmp(argv[2], "write") == 0) {
            lfs_test_write();
        } else {
            printf("app lfs read/write");
        }
	} else if (strcmp(argv[1], "http_download") == 0) {
        if (argc == 4) {
            http_download(argv[3], argv[2]);
        } else {
            printf("app http_download <save directory> <url>\n");
        }
    } else {
        print_help();
    }
}

void cli_reg_cmd_app(void)
{
    /* WiFi 测试CLI命令 */
    extern void iwpriv(char *wbuf, int wbuf_len, int argc, char **argv);
    static const struct cli_command cmd_info_wifi = {
        "iwpriv",
        "test iwpriv",
        iwpriv
    };
    aos_cli_register_command(&cmd_info_wifi);

    /* 其他CLI命令 */
    static const struct cli_command cmd_info_app = {"app", "app test cmd", cmd_app_func};
    aos_cli_register_command(&cmd_info_app);

}
